/**
 * NanoId 工具类
 * 生成安全、URL友好的唯一标识符
 */
export class NanoId {
  // 默认字符集：URL友好无歧义字符（不包含 l, I, O, 0 等易混淆字符）
  private static readonly urlAlphabet = 
    '123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz';
  
  // 默认ID长度
  private static readonly defaultSize = 21;

  /**
   * 生成默认长度的NanoId
   * @returns 长度为21的NanoId字符串
   */
  public static generate(): string {
    return this.customGenerate(this.defaultSize, this.urlAlphabet);
  }

  /**
   * 生成指定长度的NanoId
   * @param size NanoId长度
   * @returns 指定长度的NanoId字符串
   */
  public static withSize(size: number): string {
    if (size <= 0) {
      throw new Error('长度必须大于0');
    }
    return this.customGenerate(size, this.urlAlphabet);
  }

  /**
   * 使用自定义字符集生成NanoId
   * @param size NanoId长度
   * @param alphabet 使用的字符集
   * @returns NanoId字符串
   */
  public static customGenerate(size: number, alphabet: string): string {
    try {
      if (size <= 0) {
        throw new Error('长度必须大于0');
      }
      if (!alphabet || alphabet.length === 0) {
        throw new Error('字符集不能为空');
      }
      
      // 生成一个合适大小的随机值数组
      const bytes = this.getRandomBytes(size);
      
      // 生成ID
      let id = '';
      const alphabetLength = alphabet.length;
      const mask = (2 << Math.log(alphabetLength - 1) / Math.LN2) - 1;
      
      for (let i = 0; i < size; i++) {
        // 使用与运算进行掩码处理，确保均匀分布
        let randomByte = bytes[i] & mask;
        
        // 如果超出字符集范围，重新生成
        if (randomByte >= alphabetLength) {
          // 如果有crypto API可用，使用新随机字节
          if (typeof crypto !== 'undefined') {
            const newBytes = this.getRandomBytes(1);
            randomByte = newBytes[0] & mask;
            if (randomByte >= alphabetLength) continue;
          } else {
            // 否则使用Math.random回退
            randomByte = Math.floor(Math.random() * alphabetLength);
          }
        }
        
        id += alphabet[randomByte];
      }
      
      return id;
    } catch (error) {
      console.error('生成NanoId失败', error);
      return this.unsafe(size);
    }
  }
  
  /**
   * 获取安全的随机字节数组
   * @param size 需要的随机字节数量
   * @returns 随机字节数组
   */
  private static getRandomBytes(size: number): Uint8Array {
    // 使用Node.js的crypto模块或浏览器的Web Crypto API
    if (typeof crypto !== 'undefined') {
      const bytes = new Uint8Array(size);
      crypto.getRandomValues(bytes);
      return bytes;
    }
    
    // 当加密API不可用时，使用Math.random的备选方案
    const bytes = new Uint8Array(size);
    for (let i = 0; i < size; i++) {
      bytes[i] = Math.floor(Math.random() * 256);
    }
    return bytes;
  }
  
  /**
   * 生成不安全的NanoId(使用Math.random，仅作为备选方案)
   * @param size NanoId长度
   * @returns NanoId字符串
   */
  private static unsafe(size: number = this.defaultSize): string {
    let id = '';
    const alphabet = this.urlAlphabet;
    const alphabetLength = alphabet.length;
    
    for (let i = 0; i < size; i++) {
      id += alphabet[Math.floor(Math.random() * alphabetLength)];
    }
    
    return id;
  }
} 